package com.general.framework.core.lang;

import com.general.framework.core.constant.Constants;
import com.general.framework.core.utils.ConvertUtil;
import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author leejean
 * @ClassName: Strings
 * @Description: string处理工具类，基于apache的StringUtils扩展一些自己的方法
 * @date 2020年10月16 14:11:40
 */
public abstract class Strings extends StringUtils {

    /**
     * 判断是否数字正则表达式
     */
    public static final String REGEX_NUMBER = "\\d+(.\\d+)?[fF]?";

    /**
     * 手机正则表达式
     */
    public static final Pattern REGEX_MOBILE = Pattern.compile("^1([3-9])\\d{9}$");

    private static final char SEPARATOR = '_';

    public static final String EMPTY_JSON = "{}";

    public static final char C_BACKSLASH = '\\';

    public static final char C_DELIM_START = '{';

    public static final char C_DELIM_END = '}';

    /**
     * 对象默认值
     * @param object
     * @return
     */
    public static String defaultString(final Object object) {
        return object == null ? "" : object.toString();
    }

    /**
     * 对象默认值
     *
     * @param object
     * @return
     */
    public static String defaultString(final Object object, final String defaultStr) {
        return object == null ? defaultStr : object.toString();
    }


    /**
     * 不相等
     *
     * @param cs1
     * @param cs2
     * @return
     */
    public static boolean isNotEquals(CharSequence cs1, CharSequence cs2) {
        return !equals(cs1, cs2);
    }

    /**
     * 将字符串分割为集合
     *
     * @param str
     * @param separatorChars
     * @return
     */
    public static List<String> splitToList(final String str, final String separatorChars) {
        final String[] strArray = StringUtils.split(str, separatorChars);
        if (strArray == null || strArray.length < 1) {
            return Lists.emptyList();
        }
        return Lists.asList(strArray);
    }

    /**
     * 将目标字符串分割为List<Long>
     *
     * @param str            目标字符串
     * @param separatorChars 分隔符
     * @return
     */
    public static List<Long> splitToLongList(final String str, final String separatorChars) {
        if (Strings.isEmpty(str)) {
            return Lists.emptyList();
        }
        return Strings.splitToList(str, separatorChars).stream()
                .filter(Strings::isNotEmpty).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
    }
    /**
     * 将目标字符串分割为List<Integer>
     *
     * @param str            目标字符串
     * @param separatorChars 分隔符
     * @return
     */
    public static List<Integer> splitToIntegerList(final String str, final String separatorChars) {
        if (Strings.isEmpty(str)) {
            return Lists.emptyList();
        }
        return Strings.splitToList(str, separatorChars).stream()
                .filter(Strings::isNotEmpty).map(s -> Integer.valueOf(s.trim())).collect(Collectors.toList());
    }
    /**
     * 替换结尾字符
     *
     * @param source     字符源
     * @param length     保留的字符长度
     * @param replaceStr
     * @return
     */
    public static String replaceEnd(final String source, final int length, final String replaceStr) {
        if (source == null || source.length() <= length) {
            return source;
        }
        return source.substring(0, length) + replaceStr;
    }

    /**
     * 替换字符串
     *
     * @param source
     * @param startLen
     * @param endLen
     * @param replaceStr
     * @return
     */
    public static String replace(final String source, final Integer startLen, final Integer endLen, final String replaceStr) {
        if (Strings.isBlank(source)) {
            return source;
        }
        final int length = source.length(), lastIndex = length - endLen;
        if (length <= startLen + endLen) {
            return source;
        }
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            if (i < startLen || i >= lastIndex) {
                sb.append(source.charAt(i));
                continue;
            }
            sb.append(replaceStr);
        }
        return sb.toString();
    }

    /**
     * 替换特殊字符
     *
     * @param source
     * @return
     */
    public static String replaceSpecial(final String source) {
        if (Strings.isBlank(source)) {
            return source;
        }
        final String regEx = "[`~!@#$%^&*()+=|{}':;'\",\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        final Matcher m = Pattern.compile(regEx).matcher(source);
        final String target = m.replaceAll("").trim();
        return target;
    }

    /**
     * 是否数字
     *
     * @param num 输入的数字
     * @return
     */
    public static boolean isNumber(final String num) {
        return Strings.defaultString(num).matches(REGEX_NUMBER);
    }

    /**
     * 是否手机号
     *
     * @param mobile 手机号
     * @return
     */
    public static boolean isMobile(final String mobile) {
        if (Strings.isBlank(mobile)) {
            return false;
        }
        return REGEX_MOBILE.matcher(mobile).matches();
    }

    /**
     * 是否正确的身份证号码
     *
     * @param idCardNum
     * @return
     */
    public static boolean isIdCardNum(final String idCardNum) {
        if (Strings.isBlank(idCardNum)) {
            return false;
        }
        // 定义判别用户身份证号的正则表达式（15位或者18位，最后一位可以为字母）
        final String regularExpression =
                "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|"
                        + "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";
        final boolean matches = idCardNum.matches(regularExpression);
        return matches;
    }

    /**
     * 根据身份证获取性别 1 man 0 woman
     */
    public static Integer getGender(final String idCardNum) {
        if (Strings.isBlank(idCardNum)) {
            return 1;
        }
        int length = idCardNum.length();
        return idCardNum.charAt(length - 2) % 2;
    }

    /**
     * 根据身份证获取年龄
     */
    public static Integer getAge(final String idCardNum) {
        String dates = idCardNum.substring(6, 10);
        SimpleDateFormat df = new SimpleDateFormat("yyyy");
        String year = df.format(new Date());
        return Integer.parseInt(year) - Integer.parseInt(dates);
    }

    /**
     * 是否正确 的Url地址
     * @param url
     * @return
     */
    public static boolean isUrl(final String url) {
        if (Strings.isBlank(url)) {
            return false;
        }
        final String regular = "(http://|https://)([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?";
        final boolean matches = Pattern.matches(regular, url);
        return matches;
    }

    /**
     * 格式化文本, {} 表示占位符<br>
     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
     * 如果想输出 {} 使用 \\转义 { 即可，如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
     * 例：<br>
     * 通常使用：format("this is {} for {}", "a", "b") -> this is a for b<br>
     * 转义{}： format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
     * 转义\： format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
     *
     * @param template 文本模板，被替换的部分用 {} 表示
     * @param params   参数值
     * @return 格式化后的文本
     */
    public static String format(String template, Object... params) {
        if (Lists.isEmpty(Lists.asList(params))) {
            return template;
        }
        if (Strings.isEmpty(template) || Lists.isEmpty(Lists.asList(params))) {
            return template;
        }
        final int strPatternLength = template.length();

        // 初始化定义好的长度以获得更好的性能
        StringBuilder sbuf = new StringBuilder(strPatternLength + 50);

        int handledPosition = 0;
        int delimIndex;// 占位符所在位置
        for (int argIndex = 0; argIndex < params.length; argIndex++) {
            delimIndex = template.indexOf(EMPTY_JSON, handledPosition);
            if (delimIndex == -1) {
                if (handledPosition == 0) {
                    return template;
                } else { // 字符串模板剩余部分不再包含占位符，加入剩余部分后返回结果
                    sbuf.append(template, handledPosition, strPatternLength);
                    return sbuf.toString();
                }
            } else {
                if (delimIndex > 0 && template.charAt(delimIndex - 1) == C_BACKSLASH) {
                    if (delimIndex > 1 && template.charAt(delimIndex - 2) == C_BACKSLASH) {
                        // 转义符之前还有一个转义符，占位符依旧有效
                        sbuf.append(template, handledPosition, delimIndex - 1);
                        sbuf.append(ConvertUtil.utf8Str(params[argIndex]));
                        handledPosition = delimIndex + 2;
                    } else {
                        // 占位符被转义
                        argIndex--;
                        sbuf.append(template, handledPosition, delimIndex - 1);
                        sbuf.append(C_DELIM_START);
                        handledPosition = delimIndex + 1;
                    }
                } else {
                    // 正常占位符
                    sbuf.append(template, handledPosition, delimIndex);
                    sbuf.append(ConvertUtil.utf8Str(params[argIndex]));
                    handledPosition = delimIndex + 2;
                }
            }
        }
        // 加入最后一个占位符后所有的字符
        sbuf.append(template, handledPosition, template.length());

        return sbuf.toString();
    }
    /**
     * 是否包含字符串
     *
     * @param str  验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    public static boolean inStringIgnoreCase(String str, String... strs) {
        if (str != null && strs != null) {
            for (String s : strs) {
                if (str.equalsIgnoreCase(trim(s))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 驼峰转下划线命名
     */
    public static String toUnderScoreCase(String str) {
        if (str == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        // 前置字符是否大写
        boolean preCharIsUpperCase;
        // 当前字符是否大写
        boolean curreCharIsUpperCase;
        // 下一字符是否大写
        boolean nexteCharIsUpperCase = true;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (i > 0) {
                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
            } else {
                preCharIsUpperCase = false;
            }

            curreCharIsUpperCase = Character.isUpperCase(c);

            if (i < (str.length() - 1)) {
                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
            }

            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
                sb.append(SEPARATOR);
            } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
                sb.append(SEPARATOR);
            }
            sb.append(Character.toLowerCase(c));
        }

        return sb.toString();
    }

    /**
     * 是否为http(s)://开头
     *
     * @param link 链接
     * @return 结果
     */
    public static boolean isHttp(String link) {
        return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
    }

    public static boolean ipMatcher(String ip, String pattern){
        if (Strings.equals(ip, pattern)) {
            return true;
        }
        String[] ipScope = ip.split("\\.");
        String[] splitScope = pattern.split("\\.");
        boolean a = ipScope[0].equals(splitScope[0]) || "*".equals(splitScope[0]);
        boolean b = ipScope[1].equals(splitScope[1]) || "*".equals(splitScope[1]);
        boolean c = ipScope[2].equals(splitScope[2]) || "*".equals(splitScope[2]);
        boolean d = ipScope[3].equals(splitScope[3]) || "*".equals(splitScope[3]);
        return a && b && c && d;
    }

    /**
     * ip匹配
     * @param ip ip
     * @param patternList 支持*来通配网段，如192.168.1.*,则匹配192.168.1.[0~255]
     * @return isMatcher
     */
    public static boolean ipMatcher(String ip, List<String> patternList) {
        if (Lists.isEmpty(patternList) || Strings.isEmpty(ip)) {
            return false;
        }
        for(String pattern : patternList) {
            if (Strings.ipMatcher(ip, pattern)) {
                return true;
            }
        }
        return false;
    }

    public static boolean isNullOrZero(final CharSequence cs) {
        return Strings.isEmpty(cs) || Objects.equals(cs, "0");
    }

    public static boolean isNullOrZero(final Object obj) {
        return Objects.isNull(obj) || Objects.equals(obj, "0");
    }

}
